#include "ziputility.h"

wxString ZipUtility::s_lastError = wxEmptyString;

bool ZipUtility::ZipDirectory(const wxString& directory, const wxString& zipFilename)
{
    s_lastError.Clear();

    // 检查源目录是否存在
    if (!wxFileName::DirExists(directory)) {
        s_lastError = wxString::Format("源目录不存在: %s", directory);
        return false;
    }

    // 创建输出文件流
    wxFFileOutputStream out(zipFilename);
    if (!out.IsOk()) {
        s_lastError = wxString::Format("无法创建ZIP文件: %s", zipFilename);
        return false;
    }

    // 创建ZIP输出流
    wxZipOutputStream zip(out);
    if (!zip.IsOk()) {
        s_lastError = "无法初始化ZIP输出流";
        return false;
    }

    // 遍历目录
    wxDir dir(directory);
    if (!dir.IsOpened()) {
        s_lastError = wxString::Format("无法打开目录: %s", directory);
        return false;
    }

    wxString filename;
    bool cont = dir.GetFirst(&filename);
    while (cont) {
        wxString fullPath = wxFileName(directory, filename).GetFullPath();

        // 跳过当前目录和父目录
        if (filename == "." || filename == "..") {
            cont = dir.GetNext(&filename);
            continue;
        }

        // 如果是目录，递归处理
        if (wxFileName::DirExists(fullPath)) {
            if (!AddDirectoryToZip(zip, fullPath, directory)) {
                return false;
            }
        }
        // 如果是文件，添加到ZIP
        else {
            if (!AddFileToZip(zip, fullPath, directory)) {
                return false;
            }
        }

        cont = dir.GetNext(&filename);
    }

    // 关闭ZIP流
    zip.Close();
    out.Close();

    return true;
}

bool ZipUtility::AddDirectoryToZip(wxZipOutputStream& zip, const wxString& dirPath, const wxString& baseDir)
{
    // 在ZIP中创建目录条目
    wxString entryName = dirPath.substr(baseDir.length() + 1) + wxFileName::GetPathSeparator();
    if (!zip.PutNextEntry(entryName)) {
        s_lastError = wxString::Format("无法在ZIP中创建目录条目: %s", entryName);
        return false;
    }

    // 递归处理目录内容
    wxDir dir(dirPath);
    if (!dir.IsOpened()) {
        s_lastError = wxString::Format("无法打开目录: %s", dirPath);
        return false;
    }

    wxString filename;
    bool cont = dir.GetFirst(&filename);
    while (cont) {
        wxString fullPath = wxFileName(dirPath, filename).GetFullPath();

        if (filename == "." || filename == "..") {
            cont = dir.GetNext(&filename);
            continue;
        }

        if (wxFileName::DirExists(fullPath)) {
            if (!AddDirectoryToZip(zip, fullPath, baseDir)) {
                return false;
            }
        } else {
            if (!AddFileToZip(zip, fullPath, baseDir)) {
                return false;
            }
        }

        cont = dir.GetNext(&filename);
    }

    return true;
}

bool ZipUtility::AddFileToZip(wxZipOutputStream& zip, const wxString& filePath, const wxString& baseDir)
{
    // 打开文件
    wxFFileInputStream in(filePath);
    if (!in.IsOk()) {
        s_lastError = wxString::Format("无法打开文件: %s", filePath);
        return false;
    }

    // 创建ZIP条目
    wxString entryName = filePath.substr(baseDir.length() + 1);
    if (!zip.PutNextEntry(entryName)) {
        s_lastError = wxString::Format("无法在ZIP中创建文件条目: %s", entryName);
        return false;
    }

    // 写入文件内容
    zip.Write(in);

    return true;
}

bool ZipUtility::UnzipFile(const wxString& zipFilename, const wxString& targetDir)
{
    s_lastError.Clear();

    // 检查ZIP文件是否存在
    if (!wxFileName::FileExists(zipFilename)) {
        s_lastError = wxString::Format("ZIP文件不存在: %s", zipFilename);
        return false;
    }

    // 检查目标目录是否存在，不存在则创建
    if (!wxFileName::DirExists(targetDir)) {
        if (!wxFileName::Mkdir(targetDir, 0777, wxPATH_MKDIR_FULL)) {
            s_lastError = wxString::Format("无法创建目标目录: %s", targetDir);
            return false;
        }
    }

    // 打开ZIP文件输入流
    wxFFileInputStream in(zipFilename);
    if (!in.IsOk()) {
        s_lastError = wxString::Format("无法打开ZIP文件: %s", zipFilename);
        return false;
    }

    // 创建ZIP输入流
    wxZipInputStream zip(in);
    if (!zip.IsOk()) {
        s_lastError = "无法初始化ZIP输入流";
        return false;
    }

    // 遍历ZIP文件中的所有条目
    wxZipEntry* entry;
    while ((entry = zip.GetNextEntry()) != nullptr) {
        // 自动释放entry内存
        wxScopedPtr<wxZipEntry> entryPtr(entry);

        wxString name = entry->GetName();
        wxString fullPath = wxString::Format("%s\\%s",targetDir,name);

        // 如果是目录条目
        if (entry->IsDir()) {
            if (!wxFileName::Mkdir(fullPath, 0777, wxPATH_MKDIR_FULL)) {
                s_lastError = wxString::Format("无法创建目录: %s", fullPath);
                return false;
            }
        }
        // 如果是文件条目
        else {
            // 确保父目录存在
            wxFileName fn(fullPath);
            if (!fn.DirExists()) {
                if (!fn.Mkdir(0777, wxPATH_MKDIR_FULL)) {
                    s_lastError = wxString::Format("无法创建文件所在目录: %s", fn.GetPath());
                    return false;
                }
            }

            // 创建输出文件流
            wxFFileOutputStream out(fullPath);
            if (!out.IsOk()) {
                s_lastError = wxString::Format("无法创建文件: %s", fullPath);
                return false;
            }

            // 写入文件内容
            zip.Read(out);
            out.Close();

            // 设置文件修改时间为ZIP条目中的时间
            /*if (entry->GetDateTime().IsValid()) {
                wxFileName fn(fullPath);
                if (!fn.Touch(entry->GetDateTime())) {
                    wxLogWarning("无法设置文件时间: %s", fullPath);
                    // 这不是致命错误，可以继续
                }
            }*/
        }
    }

    return true;
}
